/** ------------------------------------------------------------------------
    File        : WebServiceProtocol
    Purpose     : Simple OOABL wrapper around ABL WebServices Out 
    Syntax      : 
    Description : 
    @author pjudge
    Created     : Fri Jul 02 12:01:04 EDT 2010
    Notes       : 
  ---------------------------------------------------------------------- */
routine-level on error undo, throw.

using OpenEdge.Core.XML.WebServiceProtocol.
using OpenEdge.Core.XML.WebServiceInvocationError.

using OpenEdge.Lang.DataTypeEnum.
using OpenEdge.Lang.Assert.

using Progress.Lang.SoapFaultError.
using Progress.Lang.Error.

class OpenEdge.Core.XML.WebServiceProtocol abstract:
    /** (mandatory) The name of the service to which we are connecting */
    define public property Service as character no-undo get. private set.
    
    /** (mandatory) The WSDL document descibing the service */
    define protected property WSDL as character no-undo get. private set.
    
    /** (optional) Any additional connection parameters */
    define protected property ConnectionParams as character no-undo get. set.
    
    /** The handle to the running webservice */
    define protected property WebServiceHandle as handle no-undo get. private set.
    
    /** The handle to the port on the running webservice */
    define protected property PortHandle as handle no-undo get. private set.
    
    /** (derived) Returns whether the service is currently connected. */
    define public property Connected as logical no-undo 
        get():
            return (valid-handle(WebServiceHandle) and WebServiceHandle:connected()).
        end get.
    
    constructor public WebServiceProtocol(pcService as character,
                                          pcWSDL as character,
                                          pcConnectionParams as character):
        Assert:ArgumentNotNullOrEmpty(pcService, 'Service').
        Assert:ArgumentNotNullOrEmpty(pcWSDL, 'WSDL').
                                                      
        assign Service = pcService
               WSDL = pcWSDL
               ConnectionParams = pcConnectionParams.
    end constructor.
    
    destructor public WebServiceProtocol():
        DisconnectService().
    end destructor.
    
    /** Executes an operation in a port on the WebService. This is a generalised method;
        concrete implementors can execute their operations using this method or using 
        a more specialised call.
        
        @param character The port type
        @param character The operation name
        @param longchar The request SOAP message
        @return longchar The return SOAP message.       */
    method public longchar ExecuteOperation(input pcPortTypeName as character,
                                            input pcOperationName as character,
                                            input pcInputParam as longchar):
        
        define variable cOutputParam as longchar no-undo.
        
        ConnectService().
        
        run value(pcOperationName) in ConnectPortType(pcPortTypeName) (input pcInputParam, output cOutputParam).
        
        return cOutputParam.
        
        catch eError as Error:
            undo, throw new WebServiceInvocationError(eError, pcOperationName, this-object:Service, '').
        end catch.
        finally:
            DisconnectPortType().
            DisconnectService().
        end finally.
    end method.
    
    /** Connects to the service. */
    method public void ConnectService():
        define variable cConnectString as character no-undo.
        
        if not this-object:Connected then
        do:
            cConnectString = substitute('-S &1 -WSDL &2 &3',
                                this-object:Service,
                                this-object:WSDL,
                                this-object:ConnectionParams).
            create server WebServiceHandle.
            WebServiceHandle:connect(cConnectString).
        end.
        catch eError as Error:
            delete object WebServiceHandle no-error.
            undo, throw new WebServiceInvocationError(eError, 'ConnectService', this-object:Service, '').
        end catch.        
    end method.
    
    /** Disconnects from the service, if connected. */
    method public void DisconnectService():
        if this-object:Connected then
            WebServiceHandle:disconnect().
        delete object WebServiceHandle no-error.
    end method.
    
    /** Connects to the specified port type.
        
        @param character The port type 
        @return handle The port on which to run the operation.  */
    method protected handle ConnectPortType(input pcPortType as character):
        if not this-object:Connected then
            undo, throw new WebServiceInvocationError(
                    pcPortType,
                    this-object:Service,
                    '  - service not connected').
        
        run value(pcPortType) set PortHandle on server WebServiceHandle.
        
        return PortHandle.
    end method.
    
    /**  Disconnects the currently-connected port type */
    method protected handle DisconnectPortType():
        delete object PortHandle no-error.
    end method.
    
    method static public character XmlTypeFromABL(input pcABLType as longchar):
        define variable cXmlType as character no-undo.
        
        case string(pcABLType):
            when 'datetime' then cXmlType = 'dateTime'.
            when 'logical' then  cXmlType = 'boolean'.
            when 'character' then  cXmlType = 'string'.
            otherwise cXmlType = lc(pcABLType).
        end case.
        
        return cXmlType.
    end method.
    
end class.